#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""
@File Name: 顶层窗口的_图标文件配置_退出协议设定_windows.py
@Author: LTisme
@Date: 2021/8/29 15:18
# -----------------------------------------------------------------------------------------------------
@Description: 
里面的destroy函数都是安静退出函数，quit函数则是会弹出确认窗口问询是否退出的
# -----------------------------------------------------------------------------------------------------
"""
import os
import glob
from tkinter import Tk, Toplevel, Frame, YES, BOTH, RIDGE
from tkinter.messagebox import showinfo, askyesno


class _window:
    """
    Mixin混合类，这种类只包含了其他类要使用的方法，但不必充当其他类的父类因为它没有__init__方法；
    Mixin鼓励代码重用，并且可以用于避免多重继承可能导致（“如钻石问题”）的继承歧义；
    其下的方法可被主窗口和pop-up出来的窗口获得
    """
    foundicon = None                                        # 会被所有的实例获得
    iconpatt = '*.ico'                                      # 也可以自己设置语法，要用这个语法让glob函数找到图标文件
    iconmine = 'py.ico'

    def configBorders(self, appname: '这个窗口的 名字', kind: "表示当前所处的 类型名", iconfile: '图标文件的 路径名'):
        if not iconfile:                                    # 如果未指定图标文件，则在当前文件所处目录下查找
            iconfile = self.findIcon()
        title = appname
        if kind:
            title += ' - ' + kind
        self.title(title)                                   # 让窗口显示app名字+当前的类型名
        self.iconname(appname)                              # 这个会在最小化的时候展示
        if iconfile:
            try:
                self.iconbitmap(iconfile)
            except:
                pass
        self.protocol('WM_DELETE_WINDOW', self.quit)        # 不自行关闭，因为它用protocol拦截了关闭

    def findIcon(self):
        if _window.foundicon:                               # 如果已经找到了一个图标就直接返回
            return _window.foundicon
        iconfile = None
        iconshere = glob.glob(self.iconpatt)                # 先尝试原设定的图标语法看能否找到想要的图标
        if iconshere:                                       # 找到的话就优先取第一个
            iconfile = iconshere[0]
        else:                                               # 找不到的话则尝试在此模块所在的目录里查找
            mydir = os.path.dirname(__file__)
            myicon = os.path.join(mydir, self.iconmine)
            if os.path.exists(myicon):
                iconfile = myicon
        _window.foundicon = iconfile                        # 如果找到了，就不需要再让之后的实例再找一次了；找不到就用tk默认的图标了
        return iconfile


class MainWindow(Tk, _window):
    """
    当在主要的顶级窗口运行时
    tkinter知识复习：
    destroy->关闭一个窗口（及其子窗口），但是它这里重写了destroy为Tk.quit()也就是退出整个应用
    quit->会立即终止整个应用程序并且关闭所有窗口
    所以在未重写的情况下，原生的quit会比destroy程度更深
    """
    def __init__(self, appname, kind='', iconfile=None):
        self.findIcon()
        Tk.__init__(self)
        self.__appname = appname
        self.configBorders(appname, kind, iconfile)

    def quit(self):
        if self.okayToQuit():                                # 线程是否在运行中
            if askyesno(self.__appname, '确认退出程序吗？'):
                self.destroy()                               # 退出整个应用
        else:
            showinfo(self.__appname, '现在不可退出...')

    def okayToQuit(self):                                    # 用到该函数的话需要重定义，确认是否可以安全退出
        return True                                          # 例如：线程繁忙中

    def destroy(self):                                       # 自行退出应用程序
        Tk.quit(self)                                        # 如果是退出操作，重新定义


class PopupWindow(Toplevel, _window):
    """
    在次级>>>弹出窗口<<<中运行时
    """
    def __init__(self, appname, kind, iconfile=None):
        Toplevel.__init__(self)
        self.__appname = appname
        self.configBorders(appname, kind, iconfile)

    def quit(self):
        if askyesno(self.__appname, '确认退出吗'):
            self.destroy()

    def destroy(self):
        Toplevel.destroy(self)


class QuietPopupWindow(PopupWindow):
    def quit(self):
        self.destroy()                                     # 会直接关闭，不再进行确认


class ComponentWindow(Frame):
    """
    当附加到另外一个窗口时
    """
    def __init__(self, parent):                            # 如果不是一个框架
        Frame.__init__(self, parent)                       # 提供容器
        self.pack(expand=YES, fill=BOTH)
        self.config(relief=RIDGE, border=2)                # 重新配置

    def quit(self):
        showinfo('Quit', 'Not supported in attachment mode')

    # 从Frame进行销毁：自行擦除框架               # 针对关闭操作重新定义


if __name__ == '__main__':
    ss = MainWindow('haha')
    ss.mainloop()
